package libs

import (
	"crypto/md5"
	"el/app/models/request"
	"el/app/models/response"
	"el/config"
	"encoding/base64"
	"encoding/hex"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/mojocn/base64Captcha"

	"github.com/golang-module/dongle"
	"github.com/labstack/echo/v4"
	"golang.org/x/crypto/bcrypt"
)

func CreateJwt(claims *request.Claims) (string, error) {
	JWTSecret := GetJWTSecret()
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(JWTSecret)
	return token, err
}

func ParseToken(token string) (*request.Claims, error) {
	JWTSecret := GetJWTSecret()
	tokenClaims, err := jwt.ParseWithClaims(token, &request.Claims{}, func(token *jwt.Token) (interface{}, error) {
		return JWTSecret, nil
	})

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*request.Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}
	//
	return nil, err
}

func GetJWTSecret() []byte {
	server := config.GetServerConfig()
	JWTSecret := []byte(server["JWTSecret"])
	return JWTSecret
}

func Hash(password string) string {
	hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost)
	return string(hash)
}

func HashCompare(hash string, password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
	return err == nil
}

func Ok(c echo.Context, data interface{}) error {
	return Result(0, data, "ok", c)
}

func Error(c echo.Context, code int, msg string) error {
	return Result(code, nil, msg, c)
}

func Result(code int, data interface{}, msg string, c echo.Context) error {
	return c.JSON(http.StatusOK, &response.Response{
		Code: code,
		Data: data,
		Msg:  msg,
	})
}

// StringToInt string转int
func StringToInt(_str string) int64 {
	_int, err := strconv.ParseInt(_str, 10, 64) // string转int
	if err != nil {                             // 报错则默认返回0
		_int = 0
		//fmt.Println("格式转换错误，默认为0。")
		//fmt.Println(err)
	}
	return _int
}

func InStringArray(needle string, array []string) bool {
	for _, v := range array {
		if v == needle {
			return true
		}
	}
	return false
}

func Md5(str string) string {
	h := md5.New()
	io.WriteString(h, str)
	return hex.EncodeToString(h.Sum(nil))
}

func Md516(str string) string {
	return Md5(str)[8:24]
}

func Paginate(c echo.Context) request.Paginate {
	paginate := request.Paginate{}
	page, _ := strconv.Atoi(c.FormValue("page"))
	if page == 0 {
		page = 1

	}
	limit, _ := strconv.Atoi(c.FormValue("limit"))
	switch {
	case limit > 100:
		limit = 100
	case limit <= 0:
		limit = 10
	}
	offset := (page - 1) * limit
	paginate.Page = page
	paginate.Offset = offset
	paginate.Limit = limit
	return paginate
}

func Base64Decode(str string) string {
	reader := strings.NewReader(str)
	decoder := base64.NewDecoder(base64.RawStdEncoding, reader)
	// 以流式解码
	buf := make([]byte, 1024)
	// 保存解码后的数据
	dst := ""
	for {
		n, err := decoder.Read(buf)
		dst += string(buf[:n])
		if n == 0 || err != nil {
			break
		}
	}
	return dst
}

var store = base64Captcha.DefaultMemStore

func Captcha() (id string, b64s string, err error) {
	driver := base64Captcha.DefaultDriverDigit
	cp := base64Captcha.NewCaptcha(driver, store)
	return cp.Generate()
}

func Base32(str string) string {
	return dongle.Encode.FromString(str).ByBase32().ToString()
}
